#include "com_voe_VoENetwork.h"
#include "jni_api.h"
#include "OutputParam.h"
#include "common_types.h"
#include "voe_network.h"
#include "TransportImpl.h"
#include "VoEConnectionObserverImpl.h"

static TransportImpl _Transport;
static VoEConnectionObserverImpl _VoEConnectionObserver;

/*
 * Class:     com_voe_VoENetwork
 * Method:    GetInterface
 * Signature: (J)J
 */
JNIEXPORT jlong JNICALL Java_com_voe_VoENetwork_GetInterface
	(JNIEnv* env, jclass cls, jlong p_voiceEngine)
{
	return (jlong)webrtc::VoENetwork::GetInterface((webrtc::VoiceEngine*)p_voiceEngine);
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    Release
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_Release
	(JNIEnv* env, jclass cls, jlong p)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	return pVoENetwork->Release();
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    RegisterExternalTransport
 * Signature: (JILcom/voe/callback/Transport;)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_RegisterExternalTransport
	(JNIEnv* env, jclass cls, jlong p, jint channel, jobject obj)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	if(_Transport.set(env, obj))
	{
		return  pVoENetwork->RegisterExternalTransport(channel, _Transport);
	}
	return JCB_Err_Set;
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    DeRegisterExternalTransport
 * Signature: (JI)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_DeRegisterExternalTransport
	(JNIEnv* env, jclass cls, jlong p, jint channel)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	jint result = pVoENetwork->DeRegisterExternalTransport(channel);
	if(result == 0)
		_Transport.unset(env);
	return result;
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    ReceivedRTPPacket
 * Signature: (JI[B)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_ReceivedRTPPacket
  (JNIEnv* env, jclass cls, jlong p, jint channel, jbyteArray array)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	int len = (env)->GetArrayLength(array);
	unsigned char*buf = new unsigned char[len];
	jint result = pVoENetwork->ReceivedRTPPacket(channel, buf, len);
	(env)->SetByteArrayRegion(array, 0, len, (jbyte*)buf);
	delete [] buf;

	return result;
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    ReceivedRTCPPacket
 * Signature: (JI[B)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_ReceivedRTCPPacket
	(JNIEnv* env, jclass cls, jlong p, jint channel, jbyteArray array)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	int len = (env)->GetArrayLength(array);
	unsigned char* buf = new unsigned char[len];
	jint result = pVoENetwork->ReceivedRTCPPacket(channel, buf, len);
	(env)->SetByteArrayRegion(array, 0, len, (jbyte*)buf);
	delete [] buf;
	return result;
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    GetSourceInfo
 * Signature: (JILcom/voe/common/OutputParam;)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_GetSourceInfo
  (JNIEnv* env, jclass cls, jlong p, jint channel, jobject obj)
{ 
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	int rtpPort, rtcpPort;
	char ipAddr[64] = {0};
	jint result = pVoENetwork->GetSourceInfo(channel, rtpPort, rtcpPort, ipAddr);
	if(result == 0)
	{
		JniOutputBuilder job(env);
		OutputParam param(env, obj);
		param.setArray(job.add(rtpPort).add(rtcpPort).add(std::string(ipAddr)).getOutput());
	}
	return result;
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    GetLocalIP
 * Signature: (JLcom/voe/common/OutputParam;Z)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_GetLocalIP
	(JNIEnv* env, jclass cls, jlong p, jobject obj, jboolean ipv6)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	char ipAddr[64] = {0};
	jint result = pVoENetwork->GetLocalIP(ipAddr, ipv6 != 0);
	if(result == 0)
	{
		JniOutputBuilder job(env);
		OutputParam param(env, obj);
		param.setArray(job
			.add(std::string(ipAddr))
			.getOutput());
	}
	return result;
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    EnableIPv6
 * Signature: (JI)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_EnableIPv6
	(JNIEnv* env, jclass cls, jlong p, jint channel)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	return pVoENetwork->EnableIPv6(channel);
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    IPv6IsEnabled
 * Signature: (JI)Z
 */
JNIEXPORT jboolean JNICALL Java_com_voe_VoENetwork_IPv6IsEnabled
	(JNIEnv* env, jclass cls, jlong p, jint channel)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	return pVoENetwork->IPv6IsEnabled(channel);
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    SetSourceFilter
 * Signature: (JIIILjava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_SetSourceFilter
	(JNIEnv* env, jclass cls, jlong p, jint channel, jint rtpPort, jint rtcpPort, jstring ipAddr)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	return pVoENetwork->SetSourceFilter(channel, rtpPort, rtcpPort, JniHelper::j2c_string(env, ipAddr).c_str());
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    GetSourceFilter
 * Signature: (JILcom/voe/common/OutputParam;)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_GetSourceFilter
  (JNIEnv* env, jclass cls, jlong p, jint channel, jobject obj)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	int rtpPort, rtcpPort;
	char ipAddr[64] = {0};
	jint result = pVoENetwork->GetSourceFilter(channel, rtpPort, rtcpPort, ipAddr);
	if(result == 0)
	{
		JniOutputBuilder job(env);
		OutputParam param(env, obj);
		param.setArray(job.add(rtpPort).add(rtcpPort).add(std::string(ipAddr)).getOutput());
	}
	return result;
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    SetSendTOS
 * Signature: (JIIIZ)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_SetSendTOS
	(JNIEnv* env, jclass cls, jlong p, jint channel, jint DSCP, jint priority, jboolean useSetSockopt)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	return pVoENetwork->SetSendTOS(channel, DSCP, priority, useSetSockopt!=0);
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    GetSendTOS
 * Signature: (JILcom/voe/common/OutputParam;)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_GetSendTOS
	(JNIEnv* env, jclass cls, jlong p, jint channel, jobject obj)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	int DSCP, priority;
	bool useSetSockopt;
	jint result = pVoENetwork->GetSendTOS(channel, DSCP, priority, useSetSockopt);
	if(result == 0)
	{
		JniOutputBuilder job(env);
		OutputParam param(env, obj);
		param.setArray(job.add(DSCP).add(priority).add(useSetSockopt).getOutput());
	}
	return result;
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    SetSendGQoS
 * Signature: (JIZII)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_SetSendGQoS
	(JNIEnv* env, jclass cls, jlong p, jint channel, jboolean enable, jint serviceType, jint overrideDSCP)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	return pVoENetwork->SetSendGQoS(channel, enable!=0, serviceType, overrideDSCP);
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    GetSendGQoS
 * Signature: (JILcom/voe/common/OutputParam;)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_GetSendGQoS
	(JNIEnv* env, jclass cls, jlong p, jint channel, jobject obj)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	bool enabled;
	int serviceType, overrideDSCP;
	jint result = pVoENetwork->GetSendGQoS(channel, enabled, serviceType, overrideDSCP);
	if(result == 0)
	{
		JniOutputBuilder job(env);
		OutputParam param(env, obj);
		param.setArray(job.add(enabled).add(serviceType).add(overrideDSCP).getOutput());
	}
	return result;
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    SetPacketTimeoutNotification
 * Signature: (JIZI)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_SetPacketTimeoutNotification
	(JNIEnv* env, jclass cls, jlong p, jint channel, jboolean enable, jint timeoutSeconds)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	return pVoENetwork->SetPacketTimeoutNotification(channel, enable!=0, timeoutSeconds);
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    GetPacketTimeoutNotification
 * Signature: (JILcom/voe/common/OutputParam;)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_GetPacketTimeoutNotification
	(JNIEnv* env, jclass cls, jlong p, jint channel, jobject obj)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	bool enabled;
	int timeoutSeconds;
	jint result = pVoENetwork->GetPacketTimeoutNotification(channel, enabled, timeoutSeconds);
	if(result == 0)
	{
		JniOutputBuilder job(env);
		OutputParam param(env, obj);
		param.setArray(job.add(enabled).add(timeoutSeconds).getOutput());
	}
	return result;
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    RegisterDeadOrAliveObserver
 * Signature: (JILcom/voe/callback/VoEConnectionObserver;)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_RegisterDeadOrAliveObserver
  (JNIEnv* env, jclass cls, jlong p, jint channel, jobject obj)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	if(_VoEConnectionObserver.set(env, obj))
	{
		return pVoENetwork->RegisterDeadOrAliveObserver(channel, _VoEConnectionObserver);
	}
	return JCB_Err_Set;
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    DeRegisterDeadOrAliveObserver
 * Signature: (JI)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_DeRegisterDeadOrAliveObserver
  (JNIEnv* env, jclass cls, jlong p, jint channel)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	jint result = pVoENetwork->DeRegisterDeadOrAliveObserver(channel);
	if(result == 0)
		_VoEConnectionObserver.unset(env);
	return result;
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    SetPeriodicDeadOrAliveStatus
 * Signature: (JIZI)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_SetPeriodicDeadOrAliveStatus
	(JNIEnv* env, jclass cls, jlong p, jint channel, jboolean enable, jint sampleTimeSeconds)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	return pVoENetwork->SetPeriodicDeadOrAliveStatus(channel, enable!=0, sampleTimeSeconds);
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    GetPeriodicDeadOrAliveStatus
 * Signature: (JILcom/voe/common/OutputParam;)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_GetPeriodicDeadOrAliveStatus
	(JNIEnv* env, jclass cls, jlong p, jint channel, jobject obj)
{
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	bool enabled;
	int sampleTimeSeconds;
	jint result = pVoENetwork->GetPeriodicDeadOrAliveStatus(channel, enabled, sampleTimeSeconds);
	if(result == 0)
	{
		JniOutputBuilder job(env);
		OutputParam param(env, obj);
		param.setArray(job.add(enabled).add(sampleTimeSeconds).getOutput());
	}
	return result;
}

/*
 * Class:     com_voe_VoENetwork
 * Method:    SendUDPPacket
 * Signature: (JI[BLcom/voe/common/OutputParam;Z)I
 */
JNIEXPORT jint JNICALL Java_com_voe_VoENetwork_SendUDPPacket
  (JNIEnv* env, jclass cls, jlong p, jint channel, jbyteArray array, jobject obj, jboolean useRtcpSocket)
{
	int transmittedBytes = 0;
	webrtc::VoENetwork* pVoENetwork = (webrtc::VoENetwork*)p;
	int len = (env)->GetArrayLength(array);
	unsigned char* buf = new unsigned char[len];
	JniHelper::j2c_bytes(env, array, buf, len);
	jint result = pVoENetwork->SendUDPPacket(channel, buf, len, transmittedBytes, useRtcpSocket!=0);
	if(result == 0)
	{
		JniOutputBuilder job(env);
		OutputParam param(env, obj);
		param.setArray(job.add(transmittedBytes).getOutput());
	}
	delete [] buf;
	return result;
}
